//****************************************************
// Porman Project 2
// Filename: WinMain.cpp
// Date: 2009/08/15
// Author: KengYu Lin
// Modify:
//****************************************************
#include "WinMain.h"

CMyWinClass::CMyWinClass( void ) :
m_pCamera(NULL),
m_pRWindow(NULL),
m_bFinish(false),
m_bReadyForDrawing(false),
m_bMultiThreadRendering(true),
m_bReflash(true)
{
    m_pTimer = new CHRTimer();
    m_pThread = new boost::thread( &CMyWinClass::drawing, this );
}

CMyWinClass::~CMyWinClass( void )
{
    SAFEDELETE(m_pTimer);
    SAFEDELETE(m_pThread);
}

int CMyWinClass::run( void )
{
    MSG msg;
    ::ZeroMemory( &msg, sizeof(MSG) );

    while( msg.message != WM_QUIT )
	{
		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE) )
		{
            TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else										
		{
            if( m_bMultiThreadRendering )
            {
                updateGL();
                {
                    boost::unique_lock<boost::mutex> lock(m_Mutex);
                    swapGL();
                    m_bReadyForDrawing = true;
                    m_cond.notify_one();
                }
            }
            else
            {
                updateGL();
                swapGL();
                drawGL();
            }
		}
	}
    return (int)msg.wParam;
}

void CMyWinClass::drawing( void )
{
    boost::unique_lock<boost::mutex> lock(m_Mutex);
    while(!m_bFinish)
    {
        if(!m_bReadyForDrawing)
           m_cond.wait(lock);
        else
        {
           drawGL();
           m_bReadyForDrawing = false;
        }
    }
    return;
}

bool CMyWinClass::initialGL( void )
{
    Porman::RS::CRenderSystemDesc desc;
    desc.setColorFormat( 8,8,8,8 );
    desc.setDepthFormat( 24 );
    desc.setStencilFormat( 8 );

    Porman::RS::CRenderSystem* pRenderSys = new Porman::RS::CRenderSystem( desc );
    if( pRenderSys )
    {
        m_pRWindow = Porman::RS::CRenderSystem::getSingletonPtr()->createRenderWindow( m_hWnd, "MainWindow" );
        if( m_pRWindow && Porman::RS::CRenderSystem::getSingletonPtr()->initialise( m_pRWindow ) )
        {
            m_pCamera = Porman::RS::CRenderSystem::getSingletonPtr()->createRenderCamera( "MainCamera" );
            Porman::RS::CRenderSystem::getSingleton().getDevice()->setVsync(0);
            Porman::RS::CRenderSystem::getSingleton().getDevice()->endThread();
            return true;    
        }
    }
    
    assert(0);
    if( m_pCamera )
        Porman::RS::CRenderSystem::getSingletonPtr()->deleteRenderCamera( &m_pCamera );

    if( m_pRWindow )
        Porman::RS::CRenderSystem::getSingletonPtr()->deleteRenderWindow( &m_pRWindow );

    return false;
}

void CMyWinClass::resizeGL( int iWidth, int iHeight )
{

}

void CMyWinClass::updateGL( void ) 
{
    static int iSize = 10;
    static float fTimePass = 0.0f;
    static int iCount = 0;
    static bool bInvColor = false;

    if( fTimePass > 1.0f )
    {
        if( iCount < (iSize*iSize) )
        {
            if( !m_pRWindow->addViewport( m_pCamera, iCount ) )
                assert(0);
            iCount++;
        }
        else if( iCount == (iSize*iSize) && m_bReflash )
        {
            m_pRWindow->deleteAllRenderViewports();
            bInvColor = !bInvColor;
            iCount = 0;
        }
        fTimePass = 0.0f;
    }
    else
        fTimePass += static_cast<float>( m_pTimer->stopTimer() );

    m_pTimer->startTimer();
    float fDiv = 1.0f/(float)iSize;
    for( int i=0; i<iSize; i++ )
    {
        float fOffsetY = fDiv*i;
        for( int j=0; j<iSize; j++ )
        {
            float fOffsetX = fDiv*j;
            int iIdx = i*iSize + j;
            int iTemp = m_pRWindow->getNumViewports();
            if( iIdx < iTemp )
            {
                float fColor[4];
                switch( iIdx%4 )
                {
                case 0:
                    if( m_bMultiThreadRendering )
                    {
                        fColor[0] = 1.0f; fColor[1] = 0.0f; fColor[2] = 0.0f; fColor[3] = 1.0f;
                    }
                    else
                    {
                        fColor[0] = 1.0f; fColor[1] = 0.0f; fColor[2] = 1.0f; fColor[3] = 1.0f;
                    }
                    break;
                case 1:
                    if( m_bMultiThreadRendering )
                    {
                        fColor[0] = 0.0f; fColor[1] = 1.0f; fColor[2] = 0.0f; fColor[3] = 1.0f;
                    }
                    else
                    {
                         fColor[0] = 0.5f; fColor[1] = 0.5f; fColor[2] = 1.0f; fColor[3] = 1.0f;
                    }
                    break;
                case 2:
                    if( m_bMultiThreadRendering )
                    {
                        fColor[0] = 0.0f; fColor[1] = 0.0f; fColor[2] = 1.0f; fColor[3] = 1.0f;
                    }
                    else
                    {
                         fColor[0] = 0.0f; fColor[1] = 1.0f; fColor[2] = 1.0f; fColor[3] = 1.0f;
                    }
                    break;
                case 3:
                    if( m_bMultiThreadRendering )
                    {
                        fColor[0] = 1.0f; fColor[1] = 1.0f; fColor[2] = 0.0f; fColor[3] = 1.0f;
                    }
                    else
                    {
                         fColor[0] = 0.25f; fColor[1] = 1.0f; fColor[2] = 0.45f; fColor[3] = 1.0f;
                    }
                    break;
                }

                if( bInvColor )
                {
                    fColor[0] = 1.0f - fColor[0];
                    fColor[1] = 1.0f - fColor[1];
                    fColor[2] = 1.0f - fColor[2];
                }

                Porman::RS::CRenderViewport* pViewport = m_pRWindow->getViewport( iIdx );
                if( pViewport )
                {
                    pViewport->setMertics( fOffsetX, fOffsetY, fDiv, fDiv );
                    pViewport->setBackgroundColor( fColor );
                }
            }
        }
    }
}

void CMyWinClass::swapGL( void )
{
    Porman::RS::CRenderSystem::getSingleton().onSwap();
    return;
}

void CMyWinClass::drawGL( void )
{   
    Porman::RS::CRenderSystem::getSingleton().onRender();
    return;
}

void CMyWinClass::killGL( void )
{
    if( m_bMultiThreadRendering )
    {
        {
            boost::unique_lock<boost::mutex> lock(m_Mutex);
            m_bFinish = true;
            m_cond.notify_one();
        }
        m_pThread->join();
    }

    Porman::RS::CRenderSystem::getSingleton().getDevice()->beginThread();
    if( m_pCamera )
        Porman::RS::CRenderSystem::getSingletonPtr()->deleteRenderCamera( &m_pCamera );

    if( m_pRWindow )
        Porman::RS::CRenderSystem::getSingletonPtr()->deleteRenderWindow( &m_pRWindow );

    Porman::RS::CRenderSystem* pRenderSys = Porman::RS::CRenderSystem::getSingletonPtr();
    delete pRenderSys;
}

LRESULT CALLBACK CMyWinClass::_processWndProce( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{
	switch (uMsg)									// Check For Windows Messages
	{
		case WM_CLOSE:								// Did We Receive A Close Message?
		{
			PostQuitMessage(0);						// Send A Quit Message
			return 0;								// Jump Back
		}
		case WM_KEYDOWN:							
		{
            if(wParam == VK_ESCAPE)
                SendMessage( hWnd, WM_CLOSE, 0, 0 );
            else if(wParam == VK_F2)
            {
                boost::unique_lock<boost::mutex> lock(m_Mutex);
                if( m_bMultiThreadRendering )
                    m_bReadyForDrawing = false;
                m_bMultiThreadRendering = !m_bMultiThreadRendering;
            }
            else if(wParam == VK_F3)
            {
                m_bReflash = !m_bReflash;
            }
            return 0;
		}
		case WM_KEYUP:								
		{
			return 0;								
		}
		case WM_SIZE:								  // Resize The OpenGL Window
		{
            m_iW = LOWORD(lParam);
            m_iH = HIWORD(lParam);
			resizeGL(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height
			return 0;								  // Jump Back
		}
	}
    return DefWindowProc(hWnd, uMsg, wParam, lParam); 
}

int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
					HINSTANCE	hPrevInstance,		// Previous Instance
					LPSTR		lpCmdLine,			// Command Line Parameters
					int			nCmdShow)			// Window Show State
{
    CMyWinClass MyWinClass;
    bool bFullscreen = true;

    //-----------------------------------------------
	// Ask The User Which Screen Mode They Prefer:
    //-----------------------------------------------
	if( MessageBox( NULL, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO|MB_ICONQUESTION) == IDNO )
	{
		bFullscreen = false;
	}

    if( MyWinClass.create( "PormanRS Test App", 800, 600, 32, bFullscreen ) )
    {
        MyWinClass.run();
    }

    MyWinClass.kill();
    return 0;
}
